package com.esotericsoftware.yamlbeans.extend;

import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import sun.reflect.generics.reflectiveObjects.TypeVariableImpl;

import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

public class ClassUtils {

    private static class ClassSuperNode{

        /**
         * 类
         */
        Class<?> cls;

        /**
         * 子类
         */
        ClassSuperNode classSuperNode;

        ClassSuperNode(Class<?> cls, ClassSuperNode classSuperNode) {
            this.cls = cls;
            this.classSuperNode = classSuperNode;
        }

        public Class<?> getCls() {
            return cls;
        }

        public void setCls(Class<?> cls) {
            this.cls = cls;
        }

        public ClassSuperNode getClassSuperNode() {
            return classSuperNode;
        }

        public void setClassSuperNode(ClassSuperNode classSuperNode) {
            this.classSuperNode = classSuperNode;
        }
    }

    /**
     * 获取这个类的所有字段
     *
     * 包括所有父类的
     *
     * @param entityClass 类
     * @return 所有字段
     */
    public static List<Field> getByClass(Class<?> entityClass){
        return getByClass(entityClass,null);
    }

    /**
     * 获取这个类的所有字段
     *
     * 包括所有父类的,如果父类有泛型，会根据子类的实际类型替换
     *
     * @param entityClass 类
     * @return 所有字段
     */
    public static List<Field> getByClass(Class<?> entityClass , ClassSuperNode classSuperNode){
        //初始化节点
        if (classSuperNode == null) {
            classSuperNode = new ClassSuperNode(entityClass,null);
        }
        List<Field> fields = new ArrayList<>(Arrays.asList(entityClass.getDeclaredFields()));
        if (classSuperNode.getClassSuperNode() != null) {
            //如果字段有泛型则获取泛型类型
            for (int i = 0; i < fields.size(); i++) {
                Field field = fields.get(i);
                if (field.getGenericType().getClass().equals(Class.class)) {
                    continue;
                }
                if (TypeVariableImpl.class.isAssignableFrom(field.getGenericType().getClass())) {
                    //获取泛型索引
                    int typeIndex = typeVarIndex((TypeVariableImpl) field.getGenericType());
                    //获取这个索引的实际类型，向上找
                    ClassSuperNode indexNode = classSuperNode;
                    Class cls = null;
                    while (indexNode.getClassSuperNode() != null) {
                        Type genericSuperclass = indexNode.getClassSuperNode().getCls().getGenericSuperclass();
                        Type type = ((ParameterizedTypeImpl) genericSuperclass).getActualTypeArguments()[typeIndex];
                        if (type.getClass().equals(Class.class)) {
                            cls = (Class) type;
                            break;
                        } else if (ParameterizedTypeImpl.class.isAssignableFrom(type.getClass())) {
                            cls = ((ParameterizedTypeImpl) type).getRawType();
                            break;
                        }
                        //新的索引
                        typeIndex = typeVarIndex(((TypeVariableImpl) type));
                        //继续向上找
                        indexNode = indexNode.getClassSuperNode();
                    }
                    if (cls == null) {
                        continue;
                    }
                    try {
                        Field root = Field.class.getDeclaredField("root");
                        root.setAccessible(true);
                        Object rootValue = root.get(field);
                        if (rootValue != null) {
                            root.set(field,null);
                        }
                        Method copy = Field.class.getDeclaredMethod("copy");
                        copy.setAccessible(true);
                        Object result = copy.invoke(field);
                        if (rootValue != null) {
                            root.set(field,rootValue);
                        }
                        Field type = Field.class.getDeclaredField("type");
                        type.setAccessible(true);
                        type.set(result,cls);
                        fields.set(i, (Field) result);
                    } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
        if (Object.class.equals(entityClass.getSuperclass())){
            return fields;
        }
        List<Field> superFields = getByClass(entityClass.getSuperclass(),new ClassSuperNode(entityClass.getSuperclass(),classSuperNode));
        for (Field superField : superFields) {
            if (fields.stream().map(Field::getName).collect(Collectors.toList()).contains(superField.getName())){
                continue;
            }
            fields.add(superField);
        }
        return fields;
    }

    /**
     * 获取这个字段的泛型在类泛型的Index
     * @param typeVariable
     * @return
     */
    private static int typeVarIndex(TypeVariableImpl typeVariable) {
        TypeVariable[] var1 = typeVariable.getGenericDeclaration().getTypeParameters();
        int var2 = -1;
        TypeVariable[] var3 = var1;
        int var4 = var1.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            TypeVariable var6 = var3[var5];
            ++var2;
            if (typeVariable.equals(var6)) {
                return var2;
            }
        }
        return -1;
    }
}
